﻿// Copyright © 2011 Paul Vanukoff (pvanukoff@gmail.com)

using System;
using Bravura.Contracts.PluginTypes;
using Bravura.Core.PluginLib;
using Bravura.Native.PluginBase;

namespace Bravura.Native.Plugins.Filters
{
	/// <summary>
	/// A reverb implemented as a set of very short delays, with decaying random amplitudes.
	/// WORK IN PROGRESS
	/// </summary>
	public class Reverb : Filter, IFilter
	{
		#region Fields

		#region Configuration Values

		/// <summary>
		/// Amplitude of the impulse response.
		/// </summary>
		private double _irAmp;

		/// <summary>
		/// Dropoff of the impulse response.
		/// </summary>
		private double _irPow;

		/// <summary>
		/// Length of the reverb (in samples).
		/// </summary>
		private int _kLen;

		/// <summary>
		/// Number of overlapped delays to use. More sounds better but is slower to process.
		/// </summary>
		private int _num;

		/// <summary>
		/// Maximum amount of jitter for each delay.
		/// </summary>
		private double _jitterAmt;

		#endregion

		#region Working Values

		private int _bPos = 0;
		private int _bLen = 0;
		private double[] _buffer = null; // working buffer
		private double[] _kernel = null; // generated impulse response
		private int[] _jitterVals = null; // jitter amount for each delay

		#endregion

		#endregion

		#region Properties

		// TODO

		#endregion

		public Reverb(IAudioPluginHost host, int sampleRate) : base(host, sampleRate)
		{
			_irAmp = 4.0;
			_irPow = 3.0;
			_kLen = 6 * 48000;
			_num = 50;
			_jitterAmt = 0.5;
		}

		#region Open / Process / Close

		public override void Open()
		{
			// create impulse response buffer
			_kernel = new double[_kLen];
			double amp = _irAmp / _num;
			for (int i = 0; i < _kLen; i++)
			{
				double v =  (double)(_kLen - i) / (double)_kLen;
				_kernel[i] = amp * (Math.Pow(v, _irPow)) * (Utilities.Random.NextDouble() - 0.5);
			}

			// build jitter array
			int jmax = (int)(_jitterAmt * _kLen / _num);
			_jitterVals = new int[_num];
			for (int i = 0; i < _num; i++)
			{
				_jitterVals[i] = Utilities.Random.Next(jmax);
			}

			// create working buffer
			_bLen = _kLen + 100;
			_buffer = new double[_bLen];
		}

		public override void Process(int count)
		{
			// read input buffer
			double[] ioBuff = GetInputBuffer(0).Read(count);

			// process
			int fac = _kLen / _num;
			for (int i = 0; i < count; i++)
			{
				// get input sample
				double vIn = ioBuff[i];

				// do the reverb (calculate and add all delays)
				for (int k = 0; k < _num; k++)
				{
					int t = _bPos + k * fac + _jitterVals[k];
					if (t >= _bLen) t = t % _bLen;
					_buffer[t] += vIn * _kernel[k];
				}

				// get final output sample
				ioBuff[i] = _dryMix * vIn + _wetMix * _buffer[_bPos];

				// zero the tail of the internal buffer
				_buffer[_bPos > 0 ? _bPos - 1 : _bLen - 1] = 0.0;

				// increment internal buffer pos for next time
				_bPos = (_bPos + 1) % _bLen;
			}

			// write to output buffer
			GetOutputBuffer(0).Write(ioBuff, count);
		}

		public override void Close()
		{
			//
		}

		#endregion
	}
}
